/*
 * Copyright 2020 The Netty Project
 *
 * The Netty Project licenses this file to you under the Apache License,
 * version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at:
 *
 *   https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */
package com.sample.hello1;

import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.ChannelInputShutdownReadComplete;
import io.netty.channel.socket.nio.NioDatagramChannel;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.incubator.codec.quic.QuicChannel;
import io.netty.incubator.codec.quic.QuicClientCodecBuilder;
import io.netty.incubator.codec.quic.QuicSslContext;
import io.netty.incubator.codec.quic.QuicSslContextBuilder;
import io.netty.incubator.codec.quic.QuicStreamChannel;
import io.netty.incubator.codec.quic.QuicStreamType;
import io.netty.util.CharsetUtil;
import io.netty.util.NetUtil;

public final class QuicClientExample {

	private QuicClientExample() {
	}

	public static void main(String[] args) throws Exception {
		QuicSslContext context = QuicSslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE)
				.applicationProtocols("swakx/1.1").build();
		NioEventLoopGroup group = new NioEventLoopGroup(1);
		try {
			ChannelHandler codec = new QuicClientCodecBuilder().sslContext(context)
					.maxIdleTimeout(5000, TimeUnit.MILLISECONDS).initialMaxData(10000000)
					.initialMaxStreamDataBidirectionalLocal(1000000).build();

			Bootstrap bs = new Bootstrap();
			Channel channel = bs.group(group).channel(NioDatagramChannel.class).handler(codec).bind(0).sync().channel();

			QuicChannel quicChannel = QuicChannel.newBootstrap(channel)
					// 感觉这里设置的流处理器不生效， 但不是不能不设置
					.streamHandler(new ChannelInboundHandlerAdapter() {
						@Override
						public void channelActive(ChannelHandlerContext ctx) {
							// As we did not allow any remote initiated streams we will never see this
							// method called.
							// That said just let us keep it here to demonstrate that this handle would be
							// called
							// for each remote initiated stream.
							ctx.close();
						}
					}).remoteAddress(new InetSocketAddress(NetUtil.LOCALHOST4, 9999)).connect().get();
			System.out.println("客户端：" + quicChannel);
			QuicStreamChannel streamChannel = quicChannel
					.createStream(QuicStreamType.BIDIRECTIONAL, new ChannelInitializer<QuicStreamChannel>() {
						@Override
						protected void initChannel(QuicStreamChannel ch) throws Exception {
							ch.pipeline().addLast(new EchoChannelHandler());
							ch.pipeline().addLast(new ChannelInboundHandlerAdapter() {
								@Override
								public void channelRead(ChannelHandlerContext ctx, Object msg) {
									ByteBuf byteBuf = (ByteBuf) msg;
									System.err.println(byteBuf.toString(CharsetUtil.US_ASCII));
									byteBuf.release();
								}

								@Override
								public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
									if (evt == ChannelInputShutdownReadComplete.INSTANCE) {
										// Close the connection once the remote peer did send the FIN for this stream.
										((QuicChannel) ctx.channel().parent()).close(true, 0,
												ctx.alloc().directBuffer(16)
														.writeBytes(new byte[] { 'k', 't', 'h', 'x', 'b', 'y', 'e' }));
									}
								}
							});
						}
					}).sync().getNow();

//			QuicStreamChannel streamChannel = quicChannel
//					.createStream(QuicStreamType.BIDIRECTIONAL, new ChannelInboundHandlerAdapter() {
//						@Override
//						public void channelRead(ChannelHandlerContext ctx, Object msg) {
//							ByteBuf byteBuf = (ByteBuf) msg;
//							System.err.println(byteBuf.toString(CharsetUtil.US_ASCII));
//							byteBuf.release();
//						}
//
//						@Override
//						public void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
//							if (evt == ChannelInputShutdownReadComplete.INSTANCE) {
//								// Close the connection once the remote peer did send the FIN for this stream.
//								((QuicChannel) ctx.channel().parent()).close(true, 0, ctx.alloc().directBuffer(16)
//										.writeBytes(new byte[] { 'k', 't', 'h', 'x', 'b', 'y', 'e' }));
//							}
//						}
//					}).sync().getNow();

			streamChannel.writeAndFlush(Unpooled.copiedBuffer("GET /\r\n", CharsetUtil.US_ASCII));
			streamChannel.closeFuture().sync();
			quicChannel.closeFuture().sync();
			channel.close().sync();
		} finally {
			group.shutdownGracefully();
		}
	}
}
